///////////////////////////////////////////////////////////////////////////////
/**
 Parser Grammar file
 -------------------

 Parser process the tokens sent to it on a channel by the lexer. Processing
 involves application of rules to the token.
 */

///////////////////////////////////////////////////////////////////////////////
/*
 * The first instruction should specify the grammar type (Parser) and the
 * name of the grammar (CSVParser). This name should be same as the name of
 * the grammar file without the extension.
 *
 * AntlrWorks or Ant tasks can be used to create the CSVParser.java file from
 * this grammar file.
 */
parser grammar CSVParser;

///////////////////////////////////////////////////////////////////////////////
/*
 * Parser is customized using the following options.
 */
options {
  // We're going to use the tokens defined in our lexer grammar.
  tokenVocab = CSVLexer;
}

///////////////////////////////////////////////////////////////////////////////
/*
 * Instructions starting with '@' are called grammar actions. Grammar actions
 * are used to add code to the generated Java code. 
 */

/*
 * '@header' grammar action is used to specify the package and imported classes.
 *
 * In instruction below, we have specified the package to match our tutorial
 * layout.
 */
@header{package org.concepts.java.antlr.csv;

import java.util.HashMap;
import java.util.Map;

}

///////////////////////////////////////////////////////////////////////////////
/*
 * '@members' grammar action is used to specify Parser class member variables and
 * additional methods. Parser behavior can also be changed by overriding methods
 * that are inherited from the superclass (Parser).
 *
 * In the instructions below we add the capability in the Parser to count the
 * number of records.
 */
@members{

  private int recordCount = 0;
  
  private Map<Integer,int[]> recordData = new HashMap<Integer,int[]>();

  /**
  * Returns the number of records in the list 
  */
  public int getRecordCount() {
    return recordCount;
  }
  
  /**
   * Returns an array of integers for the given record.  
   *  
   * @param counter record counter. E.g. If there are 3 records, then
   * valid counter are 0,1,2
   * @return array of integer. Is null if invalid counter is passed in.
   */
  public int[] getRecord(int counter)  {
    return (int[]) recordData.get(counter);
  }  
  
} // @members

///////////////////////////////////////////////////////////////////////////////
/*
 * '@rulecatch' grammar action is used to customize the behavior of the
 * Parser when particular kind of exceptions are handled. 
 * 
 * In the instruction below we have changed Parser behavior to throw an 
 * exception if recognition error. The default behavior is to just output 
 * the error message to the error stream.
@rulecatch {
  catch (RecognitionException e) {
    throw e;
  }
} // @rulecatch
 */

///////////////////////////////////////////////////////////////////////////////
/*
 * Parser rules. The rules are defined using EBNF
 * http://en.wikipedia.org/wiki/Extended_Backus_Naur_Form .
 * 
 */

/**
 * CSV file consists of one or more record.
 */
file: record+;

/**
 * Record is comma separated integer tokens  that ends with
 * a new line or end of file.
 * 
 */
record
@init {
  List<Integer> integers = new ArrayList<Integer>();
}
@after {
  int[] intArray = new int[integers.size()];
  int intCtr = 0;
  for (Integer integer : integers) {
    intArray[intCtr++] = integer.intValue();
  }

  recordData.put(recordCount++, intArray);
}
  : (first = INT) 
      { integers.add(new Integer($first.text));}  
    (COMMA (other = INT) 
      {integers.add(new Integer($other.text));}
    )* 
    (NEWLINE | EOF);
    
    


///////////////////////////////////////////////////////////////////////////////
